package com.semidata.trp.decision.select;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import com.semidata.rtd.core.log.Logger;
import com.semidata.rtd.engine.job.Job;
import com.semidata.rtd.engine.job.SyncTask;
import com.semidata.trp.decision.business.Material;
import com.semidata.trp.decision.business.Strategy;
import com.semidata.trp.decision.filter.FilterResult;
import com.semidata.trp.decision.filter.TaskFilter;
import com.semidata.trp.decision.job.DecisionJob;
import com.semidata.trp.decision.job.DecisionJobContext;
import com.semidata.trp.decision.utils.SampleUtils;
import com.semidata.trp.decision.utils.Utils;

public class TaskSelect extends SyncTask {
	private List<Integer> failedIndex;
	private TaskFilter filter;
	public TaskSelect(Job job, long timeout) {
		super(job, timeout);
	}

	@Override
	public void run() {
		try {
			DecisionJob job = ((DecisionJob) getJob());
			DecisionJobContext context = job.getJobContext();
			List<FilterResult> filterResults = context.getFilterResults();
			context.setFilterResults(null);
			if (context.isHasDynamicBid()) {
				List<FilterResult> removedResults = new ArrayList<>();
				for(int index : this.getFailedIndex()) {
					removedResults.add(filterResults.get(index));
				}
				if (removedResults.size() > 0)
					filterResults.removeAll(removedResults);
				if (filterResults.size() == 0) {
					Strategy defaultStrategy = Utils.getDefaultStrategy(context.getResource(), getTaskFilter(), context.getPosition(), context.getFrequency());
					if (defaultStrategy != null){
						FilterResult defaultResult = new FilterResult(defaultStrategy);
						defaultResult.setMaterials(defaultStrategy.getMaterialWeights());
						filterResults.add(defaultResult);
					}
						
				} else {
					Collections.sort(filterResults, new Comparator<FilterResult>(){

						@Override
						public int compare(FilterResult o1, FilterResult o2) {
							// TODO Auto-generated method stub
							int c = (int) Math.signum(o2.getPrice() - o1.getPrice());
							return c;
						}
						
					});
				}
					
			}
			
			if (filterResults.size() == 0)
				throw new Exception("No result be select");
			int max = context.getPosition().getMax();
			List<FilterResult> candidates = new ArrayList<>();
			double price = context.getResource().getFloor();
			
			if (filterResults.size() > 1) {
				
				double maxPrice = 0;
				double secondPrice = 0;
				
				for (FilterResult result : filterResults) {
					double p = result.getPrice();
					if (p > maxPrice) {
						secondPrice = maxPrice;
						maxPrice = p;
						candidates = new ArrayList<>();
						candidates.add(result);
					} else if (p == maxPrice) {
						secondPrice = p;
						candidates.add(result);
					} else if (p > secondPrice) {
						secondPrice = p;
					}
				}
				price = secondPrice;
			} else {
				candidates.add(filterResults.get(0));
				if (filterResults.get(0).getPrice() == 0.0)
					price = 0.0;

			}
			if (price != 0.0)
				price = price + 0.01;
			context.setPrice(price);
			filterResults.clear();
			
			FilterResult candidate = null;
			
			if (candidates.size() > 1) {
				candidate = candidates.get((int) (candidates.size() * Math.random()));
			} else {
				candidate = candidates.get(0);
			}
			System.out.println("candidate size : " + candidates.size() + " material size : " + candidates.get(0).getMaterials().size());
			List<Material> materials = SampleUtils.weightedSample(candidate.getMaterials(), max);
			System.out.println("materials size is : " + materials.size());
			context.setSelectResult(new SelectResult(candidate.getStrategy(), materials));
		} catch (Exception e) {
			Logger.log("DEBUG", "error occurs when selecting");
			Logger.log("ERROR", e);
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}
	
	public void setFailedIndex(List<Integer> failedIndex) {
		this.failedIndex = failedIndex;
	}
	public List<Integer> getFailedIndex() {
		return this.failedIndex;
	}
	public TaskFilter getTaskFilter() {
		return this.filter;
	}
	public void setFilter(TaskFilter filter) {
		this.filter = filter;
	}
}
